package com.gxc.linkedList;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 推荐多样性需要从多个列表中选择元素，一次性要返回 N 屏数据（窗口数量），每屏展示 K 个元素（窗口大小），选择策略：
 *
 * 各个列表元素需要做穿插处理，即先从第一个列表中为每屏选择一个元素，再从第二个列表中为每屏选择一个元素，依次类推
 *
 * 每个列表的元素尽量均分为 N 份，如果不够 N 个，也要全部分配完，参考样例图：
 *
 * （1）从第一个列表中选择 4 条 0 1 2 3，分别放到 4 个窗口中
 *
 * （2）从第二个列表中选择 4 条 10 11 12 13，分别放到 4 个窗口中
 *
 * （3）从第三个列表中选择 4 条 20 21 22 23，分别放到 4 个窗口中
 *
 * （4）再从第一个列表中选择 4 条 4 5 6 7，分别放到 4 个窗口中
 *
 * …
 *
 * （5）再从第一个列表中选择，由于数量不足 4 条，取剩下的 2 条，放到 窗口1 和 窗口2
 *
 * （6）再从第二个列表中选择，由于数量不足 4 条并且总的元素数达到窗口要求，取 18 19 放到 窗口3 和 窗口4
 *
 * 输入描述
 * 第一行输入为 N，表示需要输出的窗口数量，取值范围 [1, 10]
 *
 * 第二行输入为 K，表示每个窗口需要的元素数量，取值范围 [1, 100]
 *
 * 之后的行数不定（行数取值范围 [1, 10]），表示每个列表输出的元素列表。元素之间以空格隔开，已经过排序处理，每个列表输出的元素数量取值范围 [1, 100]
 *
 * 输出描述
 * 输出元素列表，元素数量 = 窗口数量 * 窗口大小，元素之间以空格分隔，多个窗口合并为一个列表输出，参考样例：
 *
 * 先输出窗口1的元素列表，再输出窗口2的元素列表，再输出窗口3的元素列表，最后输出窗口4的元素列表
 *
 * 备注
 * 每个列表会保证元素数量满足窗口要求，不需要考虑元素不足情况
 * 每个列表的元素已去重，不需要考虑元素重复情况
 * 每个列表的元素列表均不为空，不需要考虑列表为空的情况
 * 每个列表的元素列表已经过排序处理，输出结果要保证不改变同一个列表的元素顺序
 * 每个列表的元素数量可能是不同的
 */
public class Diversity {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = Integer.parseInt(scanner.nextLine());
        int k = Integer.parseInt(scanner.nextLine());
        List<Queue<Integer>> queueList = new ArrayList<>();
        while (scanner.hasNextLine()) {
            String inputLine = scanner.nextLine();
            if (inputLine.isEmpty()) break;
            LinkedList<Integer> queue = Arrays.stream(inputLine.split(" ")).map(Integer::parseInt).collect(Collectors.toCollection(LinkedList::new));
            queueList.add(queue);
        }
        scanner.close();

        // 创建一个数组，用于存储最终的元素排列
        int[] matrix = new int[n * k];
        int matrixIndex = 0; // 用于标记当前填充到matrix数组中的位置
        int queueIndex = 0; // 用于标记当前处理的队列索引

        // 循环，直到matrix数组被完全填满
        while (matrixIndex < matrix.length) {
            boolean didRemoveQueue = false; // 标记本轮循环中是否有队列被移除

            // 遍历每个窗口，并尝试从当前队列中为每个窗口提取一个元素
            for (int i = 0; i < n && !queueList.isEmpty(); i++) {
                // 如果当前队列为空，则移除该队列
                if (queueList.get(queueIndex).isEmpty()) {
                    queueList.remove(queueIndex);
                    if (queueList.isEmpty()) break; // 如果所有队列都已处理完毕，则退出循环
                    queueIndex %= queueList.size(); // 调整队列索引，防止索引越界
                    didRemoveQueue = true;
                }
                // 如果当前队列不为空，则从队列中取出一个元素填充到matrix数组中
                if (!queueList.get(queueIndex).isEmpty()) {
                    matrix[matrixIndex++] = queueList.get(queueIndex).poll();
                    if (matrixIndex >= matrix.length) break; // 如果matrix数组已填满，则退出循环
                }
            }

            // 如果本轮循环没有队列被移除，并且队列列表不为空，则处理下一个队列
            if (!didRemoveQueue && !queueList.isEmpty()) {
                queueIndex = (queueIndex + 1) % queueList.size();
            }
        }

        // 使用StringBuilder构建最终的输出字符串
        StringBuilder sb = new StringBuilder();
        // 遍历matrix数组，按照窗口顺序构建输出字符串
        for (int row = 0; row < n; row++) {
            for (int col = 0; col < k; col++) {
                sb.append(matrix[col * n + row]).append(" ");
            }
        }

        // 输出最终的元素排列，去除末尾的空格
        System.out.println(sb.toString().trim());
    }
}
